
%include {
#include <vector>
#include <string>

using namespace std;

#include <cassert>
#include "Expr.h"
#include "ObjectSpec.h"
#include "MemberSpec.h"
#include "ClassSpec.h"
#include "QuerySpec.h"
}

%token_type      {char*}
%type expr       {Expr*}
%type objbrack   {ObjectSpec*}
%type memtype    {unsigned int}
%type memdef     {MemberSpec*}
%type memdeflist {MemberSpec*}
%type command    {unsigned int}
%type quantifier {unsigned int}
%type query      {QuerySpec*}


%start_symbol query

%right NOT.

%left BRACK_LEFT BRACK_RIGHT.
%left CURLY_LEFT CURLY_RIGHT.
%right POWER.
%left ASTERIK SLASH.
%left MOD.
%left PLUS MINUS.

%left GT LT GE LE NE EQUAL PP LG.
%left AND OR XOR.

%left COMMA.
%left SEMICOLON.

%left MG.

/* Basic definition for an expression */
expr(A) ::= IDENTIFIER(B).   { A = new Expr (TYPE_IDENTIFIER, B); }
expr(A) ::= STRING_DATA(B).  { A = new Expr (TYPE_STRING,     B); }
expr(A) ::= INTEGER_DATA(B). { A = new Expr (TYPE_INTEGER,    B); }
expr(A) ::= FLOAT_DATA(B).   { A = new Expr (TYPE_FLOAT,      B); }

/* Math operations */
expr(A) ::= expr(B) PLUS expr(C).    { A = new Expr (TYPE_OP, OP_ADD, B, C);       }
expr(A) ::= expr(B) MINUS expr(C).   { A = new Expr (TYPE_OP, OP_SUBTRACT, B, C);  }
expr(A) ::= expr(B) ASTERIK expr(C). { A = new Expr (TYPE_OP, OP_MULTIPLY, B, C);  }
expr(A) ::= expr(B) POWER expr(C).   { A = new Expr (TYPE_OP, OP_POWER, B, C);     }
expr(A) ::= expr(B) SLASH expr(C).   { A = new Expr (TYPE_OP, OP_DIVIDE, B, C);    }
expr(A) ::= expr(B) MOD expr(C).     { A = new Expr (TYPE_OP, OP_MODULO, B, C);    }
expr(A) ::= expr(B) EQUAL expr(C).   { A = new Expr (TYPE_OP, OP_ASSIGN, B, C);    }
expr(A) ::= MINUS expr(B). [NOT]     { A = new Expr (TYPE_OP, OP_NEGATE, B);       } 

/* Logical operations */
expr(A) ::= expr(B) GT expr(C).      { A = new Expr (TYPE_OP, OP_GT, B, C);        }
expr(A) ::= expr(B) LT expr(C).      { A = new Expr (TYPE_OP, OP_LT, B, C);        }
expr(A) ::= expr(B) GE expr(C).      { A = new Expr (TYPE_OP, OP_GE, B, C);        }
expr(A) ::= expr(B) LE expr(C).      { A = new Expr (TYPE_OP, OP_LE, B, C);        }
expr(A) ::= expr(B) NE expr(C).      { A = new Expr (TYPE_OP, OP_NE, B, C);        }

expr(A) ::= expr(B) AND expr(C).     { A = new Expr (TYPE_OP, OP_AND, B, C);       }
expr(A) ::= expr(B) OR expr(C).      { A = new Expr (TYPE_OP, OP_OR, B, C);        }
expr(A) ::= expr(B) XOR expr(C).     { A = new Expr (TYPE_OP, OP_XOR, B, C);       }
expr(A) ::= NOT expr(B).             { A = new Expr (TYPE_OP, OP_NOT, B);          }

/* (UN)RELATE parsing */
expr(A) ::= expr(B) PP expr(C).      { A = new Expr (TYPE_OP, OP_PP, B, C);        }
expr(A) ::= expr(B) LG expr(C).      { A = new Expr (TYPE_OP, OP_LG, B, C);        }

/* Brackets */
expr(A) ::= BRACK_LEFT expr(B) BRACK_RIGHT. { A = B; }

/* Comma-separated list of expressions */
expr(A) ::= expr(B) COMMA expr(C). { A = B; A->appendExpr (C); }

/* Object tree parsing */
objbrack(A) ::= expr(B) BRACK_LEFT expr(C) SEMICOLON 
              expr(D) SEMICOLON expr(E) BRACK_RIGHT.     { A = new ObjectSpec (B, C, D, E);       }

objbrack(A) ::= expr(B) BRACK_LEFT expr(C) BRACK_RIGHT.  { A = new ObjectSpec (B, C);             }

objbrack(A) ::= expr(B) BRACK_LEFT SEMICOLON 
                 expr(C) BRACK_RIGHT.                    { A = new ObjectSpec (B, NULL, C);       }

objbrack(A) ::= expr(B) BRACK_LEFT SEMICOLON 
                 SEMICOLON expr(C) BRACK_RIGHT.	         { A = new ObjectSpec (B, NULL, NULL, C); }

objbrack(A) ::= expr(B) BRACK_LEFT expr(C) 
                 SEMICOLON expr(D) BRACK_RIGHT.          { A = new ObjectSpec (B, C, D);          }
objbrack(A) ::= expr(B) BRACK_LEFT expr(C) SEMICOLON 
               SEMICOLON expr(D) BRACK_RIGHT.            { A = new ObjectSpec (B, C, NULL, D);    }
objbrack(A) ::= expr(B) BRACK_LEFT SEMICOLON expr(C) 
              SEMICOLON expr(D) BRACK_RIGHT.             { A = new ObjectSpec (B, NULL, C, D);    }

objbrack(A) ::= objbrack(B) COMMA objbrack(C). { A = B; A->appendObjectSpec (C); }

objbrack(A) ::= objbrack(B) expr(C) GT objbrack(D). { A = B; 
                                                      A->setRelationName  (C);
                                                      A->setChildObject   (D);   }
objbrack(A) ::= objbrack(B) expr(C) CURLY_LEFT 
                     objbrack(D)  CURLY_RIGHT. { A = B; 
                                                      A->setRelationName  (C);
                                                      A->setChildObject   (D);   }


/* member type definition parsing */
memtype(A) ::= STRING.  { A = MEMTYPE_STRING;  }
memtype(A) ::= INTEGER. { A = MEMTYPE_INTEGER; }
memtype(A) ::= FLOAT.   { A = MEMTYPE_FLOAT;   }
memtype(A) ::= TIME.    { A = MEMTYPE_TIME;    }

/* member definition parsing */
memdef(A) ::= memtype(B) expr(C).                  { A = new MemberSpec (B, C);          }
memdef(A) ::= memtype(B) expr(C) expr(D).          { A = new MemberSpec (B, C, D);       }
memdef(A) ::= memtype(B) expr(C) REDEFINE expr(D). { A = new MemberSpec (B, NULL, C, D); }      
memdef(A) ::= memtype(B) expr(C) expr(D) REDEFINE 
                expr(E).                           { A = new MemberSpec (B, C, D, E);    }

memdef(A) ::= memdef(B) SEMICOLON memdef(C).       { A = B; A->appendMemberSpec (C);     }

/* class definition parsing */
query(A) ::= CLASS expr(B) CURLY_LEFT memdef(C) CURLY_RIGHT.  { A = new QuerySpec ( QUERY_CMD_CLASS ); 
                                                                A->setClassSpec (new ClassSpec (CLASS_OP_NEW, B, C));    }

/* class redefinition parsing */
query(A) ::= CHANGE expr(B) CURLY_LEFT memdef(C) CURLY_RIGHT. { A = new QuerySpec ( QUERY_CMD_CLASS ); 
                                                                A->setClassSpec (new ClassSpec (CLASS_OP_CHANGE, B, C)); }

/* Relate/unrelate parsing */
quantifier(A) ::= ONE.  { A = QUANTIFIER_ONE;  }
quantifier(A) ::= MANY. { A = QUANTIFIER_MANY; }

query(A) ::= RELATE   quantifier(B) expr(C) 
             expr(D) quantifier(E) expr(F). { A = new QuerySpec ( QUERY_CMD_RELATE );
                                              A->setSourceQuantifier (B);
                                              A->setSourceClass      (C);
                                              A->setRelationName     (D);
                                              A->setDestQuantifier   (E);
                                              A->setDestClass        (F);
                                            }
query(A) ::= UNRELATE expr(B) expr(C) expr(D). { A = new QuerySpec ( QUERY_CMD_UNRELATE );
                                                 A->setSourceClass      (C);
                                                 A->setRelationName     (D);
                                                 A->setDestClass        (F);
                                               }

/* Query commands */
command(A) ::= GET.      { A = QUERY_CMD_GET;      }
command(A) ::= DELETE.   { A = QUERY_CMD_DELETE;   }
command(A) ::= UPDATE.   { A = QUERY_CMD_UPDATE;   }
command(A) ::= ADD.      { A = QUERY_CMD_ADD;      }
command(A) ::= LINK.     { A = QUERY_CMD_LINK;     }
command(A) ::= DELINK.   { A = QUERY_CMD_DELINK;   }

/* Query commands  */
query(A) ::= command(B) objbrack(C). { A = new QuerySpec ( B, C ); }
query(A) ::= command(B) expr(C).     { A = new QuerySpec ( B, C ); }
